<!DOCTYPE html>
<html>
<head>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id='UA-133422980-2"></script>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());

	  gtag('config', 'UA-133422980-2');
	</script>

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>
		gem5: Declaring a state machine 
	</title>

	<!-- SITE FAVICON -->
	<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>

	<link rel="canonical" href="http://localhost:4000/documentation/learning_gem5/part3/cache-declarations/">
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>

	<!-- FAVICON -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

	<!-- BOOTSTRAP -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

	<!-- CUSTOM CSS -->
	<link rel="stylesheet" href="/css/main.css">
</head>


<body>
	<nav class="navbar navbar-expand-md navbar-light bg-light">
  <a class="navbar-brand" href="/">
		<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=55px>
	</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <!-- LIST FOR NAVBAR -->
    <ul class="navbar-nav ml-auto">
      <!-- HOME -->
      <li class="nav-item ">
        <a class="nav-link" href="/">Home</a>
      </li>

      <!-- ABOUT -->
			<li class="nav-item dropdown ">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					About
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="/about">About gem5</a>
          <a class="dropdown-item" href="/publications">Publications</a>
          <a class="dropdown-item" href="/governance">Governance</a>
				</div>
			</li>

      <!-- DOCUMENTATION -->
			<li class="nav-item dropdown active">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					Documentation
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
					<!-- Pull navigation from _data/documentation.yml -->
					
            <a class="dropdown-item" href="/documentation">gem5 documentation</a>
					
            <a class="dropdown-item" href="/documentation/learning_gem5/introduction">Learning gem5</a>
					
            <a class="dropdown-item" href="http://doxygen.gem5.org/release/current/index.html">gem5 Doxygen</a>
					
            <a class="dropdown-item" href="/documentation/reporting_problems">Reporting Problems</a>
					
				</div>
			</li>

      <!-- EVENTS -->
			<li class="nav-item dropdown ">
        <a class="nav-link" href="/events/">Events</a>
			</li>

      <!-- CONTRIBUTING -->
      <li class="nav-item ">
        <a class="nav-link" href="/contributing">Contributing</a>
      </li>

      <!-- BLOG -->
      <li class="nav-item ">
        <a class="nav-link" href="/blog">Blog</a>
      </li>

      <!-- SEARCH -->
			<li class="nav-item ">
        <a class="nav-link" href="/search">Search</a>
      </li>
    </ul>
  </div>
</nav>

	<main>
		<div class="sidenav-top">
  <div class="sidenav-brand bg-light">
    <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="55px"></a>
  </div>
  <div class="search">
    <form action="/search" method="get">
      <!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
      <input type="text" name="query">
      <button type="submit" name="submit"><i class="fa fa-search"></i></button>
    </form>
  </div>
</div>
<div class="sidenav">
  <!-- Pull navigation from _data/documentation.yml -->
  
    
  
    
    
      <a class="item" href="/documentation/learning_gem5/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
        Introduction
      </a>
      <div class="collapse " id="introduction">
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part1" role="button" aria-expanded="false" aria-controls="collapseExample">
        Getting Started
      </a>
      <div class="collapse " id="part1">
        
          <a class="subitem " href="/documentation/learning_gem5/part1/building">Building gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/simple_config">Creating a simple configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/cache_config">Adding cache to configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/gem5_stats">Understanding gem5 statistics and output</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/example_configs">Using the default configuration scripts</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part2" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modifying/Extending
      </a>
      <div class="collapse " id="part2">
        
          <a class="subitem " href="/documentation/learning_gem5/part2/environment">Setting up your development environment</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/helloobject">Creating a very simple SimObject</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/debugging">Debugging gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/events">Event-driven programming</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/parameters">Adding parameters to SimObjects and more events</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/memoryobject">Creating SimObjects in the memory system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/simplecache">Creating a simple cache object</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part3" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modeling Cache Coherence with Ruby
      </a>
      <div class="collapse show" id="part3">
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIintro">Introduction to Ruby</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-intro">MSI example cache protocol</a>
        
          <a class="subitem active" href="/documentation/learning_gem5/part3/cache-declarations">Declaring a state machine</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-in-ports">In port code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-actions">Action code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-transitions">Transition code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/directory">MSI Directory implementation</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIbuilding">Compiling a SLICC protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/configuration">Configuring a simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/running">Running the simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIdebugging">Debugging SLICC Protocols</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/simple-MI_example">Configuring for a standard protocol</a>
        
      </div>
    
      <a class="item" href="/documentation/learning_gem5/gem5_101/" role="button" aria-expanded="false" aria-controls="collapseExample">
        gem5 101
      </a>
      <div class="collapse " id="gem5_101">
        
      </div>
    
    
  
    
  
    
  
</div>


<div class="container" id="doc-container">
  <div class="edit"><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Edit this page</a></div>
  <b>authors:</b> Jason Lowe-Power<br>
  

  <br>
  <h1 id="declaring-a-state-machine">Declaring a state machine</h1>

<p>Let’s start on our first state machine file! First, we will create the
L1 cache controller for our MSI protocol.</p>

<p>Create a file called <code class="highlighter-rouge">MSI-cache.sm</code> and the following code declares the
state machine.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">machine</span><span class="p">(</span><span class="n">MachineType</span><span class="o">:</span><span class="n">L1Cache</span><span class="p">,</span> <span class="s">"MSI cache"</span><span class="p">)</span>
    <span class="o">:</span> <span class="o">&lt;</span><span class="n">parameters</span><span class="o">&gt;</span>
<span class="p">{</span>
    <span class="o">&lt;</span><span class="n">All</span> <span class="n">state</span> <span class="n">machine</span> <span class="n">code</span><span class="o">&gt;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The first thing you’ll notice about the state machine code is that is
looks very C++-like. The state machine file is like creating a C++
object in a header file, if you included all of the code there as well.
When in doubt, C++ syntax with <em>probably</em> work in SLICC. However, there
are many cases where C++ syntax is incorrect syntax for SLICC as well as
cases where SLICC extends the syntax.</p>

<p>With <code class="highlighter-rouge">MachineType:L1Cache</code>, we are naming this state machine <code class="highlighter-rouge">L1Cache</code>.
SLICC will generate many different objects for us from the state machine
using that name. For instance, once this file is compiled, there will be
a new SimObject: <code class="highlighter-rouge">L1Cache_Controller</code> that is the cache controller. Also
included in this declaration is a description of this state machine:
“MSI cache”.</p>

<p>There are many cases in SLICC where you must include a description to go
along with the variable. The reason for this is that SLICC was
originally designed to just describe, not implement, coherence
protocols. Today, these extra descriptions serve two purposes. First,
they act as comments on what the author intended each variable, or
state, or event, to be used for. Second, many of them are still exported
into HTML when building the HTML tables for the SLICC protocol. Thus,
while browsing the HTML table, you can see the more detailed comments
from the author of the protocol. It is important to be clear with these
descriptions since coherence protocols can get quite complicated.</p>

<h2 id="state-machine-parameters">State machine parameters</h2>

<p>Proceeding the <code class="highlighter-rouge">machine()</code> declaration is a colon, after which all of
the parameters to the state machine are declared. These parameters are
directly exported to the SimObject that is generated by the state
machine.</p>

<p>For our MSI L1 cache, we have the following parameters:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">machine</span><span class="p">(</span><span class="n">MachineType</span><span class="o">:</span><span class="n">L1Cache</span><span class="p">,</span> <span class="s">"MSI cache"</span><span class="p">)</span>
<span class="o">:</span> <span class="n">Sequencer</span> <span class="o">*</span><span class="n">sequencer</span><span class="p">;</span>
  <span class="n">CacheMemory</span> <span class="o">*</span><span class="n">cacheMemory</span><span class="p">;</span>
  <span class="kt">bool</span> <span class="n">send_evictions</span><span class="p">;</span>

  <span class="o">&lt;</span><span class="n">Message</span> <span class="n">buffer</span> <span class="n">declarations</span><span class="o">&gt;</span>

  <span class="p">{</span>

  <span class="p">}</span>
</code></pre></div></div>

<p>First, we have a <code class="highlighter-rouge">Sequencer</code>. This is a special class that is
implemented in Ruby to interface with the rest of gem5. The Sequencer is
a gem5 <code class="highlighter-rouge">MemObject</code> with a slave port so it can accept memory requests
from other objects. The sequencer accepts requests from a CPU (or other
master port) and converts the gem5 the packet into a <code class="highlighter-rouge">RubyRequest</code>.
Finally, the <code class="highlighter-rouge">RubyRequest</code> is pushed onto the <code class="highlighter-rouge">mandatoryQueue</code> of the
state machine. We will revisit the <code class="highlighter-rouge">mandatoryQueue</code> in
the <a href="../cache-in-ports">in-port section</a>.</p>

<p>Next, there is a <code class="highlighter-rouge">CacheMemory</code> object. This is what holds the cache data
(i.e., cache entries). The exact implementation, size, etc. is
configurable at runtime.</p>

<p>Finally, we can specify any other parameters we would like, similar to a
general <code class="highlighter-rouge">SimObject</code>. In this case, we have a boolean variable
<code class="highlighter-rouge">send_evictions</code>. This is used for out-of-order core models to notify
the load-store queue if an address is evicted after a load to squash a
load if it is speculative.</p>

<p>Next, also in the parameter block (i.e., before the first open bracket),
we need to declare all of the message buffers that this state machine
will use. Message buffers are the interface between the state machine
and the Ruby network. Messages are sent and received via the message
buffers. Thus, for each virtual channel in our protocol we need a
separate message buffer.</p>

<p>The MSI protocol needs three different virtual networks. Virtual
networks are needed to prevent deadlock (e.g., it is bad if a response
gets stuck behind a stalled request). In this protocol, the highest
priority is responses (virtual network 2), followed by forwarded
requests (virtual network 1), then requests have the lowest priority
(virtual network 0). See Sorin et al. for details on why these three
virtual networks are needed.</p>

<p>The following code declares all of the needed message buffers.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">machine</span><span class="p">(</span><span class="n">MachineType</span><span class="o">:</span><span class="n">L1Cache</span><span class="p">,</span> <span class="s">"MSI cache"</span><span class="p">)</span>
<span class="o">:</span> <span class="n">Sequencer</span> <span class="o">*</span><span class="n">sequencer</span><span class="p">;</span>
  <span class="n">CacheMemory</span> <span class="o">*</span><span class="n">cacheMemory</span><span class="p">;</span>
  <span class="kt">bool</span> <span class="n">send_evictions</span><span class="p">;</span>

  <span class="n">MessageBuffer</span> <span class="o">*</span> <span class="n">requestToDir</span><span class="p">,</span> <span class="n">network</span><span class="o">=</span><span class="s">"To"</span><span class="p">,</span> <span class="n">virtual_network</span><span class="o">=</span><span class="s">"0"</span><span class="p">,</span> <span class="n">vnet_type</span><span class="o">=</span><span class="s">"request"</span><span class="p">;</span>
  <span class="n">MessageBuffer</span> <span class="o">*</span> <span class="n">responseToDirOrSibling</span><span class="p">,</span> <span class="n">network</span><span class="o">=</span><span class="s">"To"</span><span class="p">,</span> <span class="n">virtual_network</span><span class="o">=</span><span class="s">"2"</span><span class="p">,</span> <span class="n">vnet_type</span><span class="o">=</span><span class="s">"response"</span><span class="p">;</span>

  <span class="n">MessageBuffer</span> <span class="o">*</span> <span class="n">forwardFromDir</span><span class="p">,</span> <span class="n">network</span><span class="o">=</span><span class="s">"From"</span><span class="p">,</span> <span class="n">virtual_network</span><span class="o">=</span><span class="s">"1"</span><span class="p">,</span> <span class="n">vnet_type</span><span class="o">=</span><span class="s">"forward"</span><span class="p">;</span>
  <span class="n">MessageBuffer</span> <span class="o">*</span> <span class="n">responseFromDirOrSibling</span><span class="p">,</span> <span class="n">network</span><span class="o">=</span><span class="s">"From"</span><span class="p">,</span> <span class="n">virtual_network</span><span class="o">=</span><span class="s">"2"</span><span class="p">,</span> <span class="n">vnet_type</span><span class="o">=</span><span class="s">"response"</span><span class="p">;</span>

  <span class="n">MessageBuffer</span> <span class="o">*</span> <span class="n">mandatoryQueue</span><span class="p">;</span>

<span class="p">{</span>

<span class="p">}</span>
</code></pre></div></div>

<p>We have five different message buffers: two “To”, two “From”, and one
special message buffer. The “To” message buffers are similar to slave
ports in gem5. These are the message buffers that this controller uses
to send messages to other controllers in the system. The “From” message
buffers are like slave ports. This controller receives messages on
“From” buffers from other controllers in the system.</p>

<p>We have two different “To” buffers, one for low priority requests, and
one for high priority responses. The priority for the networks are not
inherent. The priority is based on the order that other controllers look
at the message buffers. It is a good idea to number the virtual networks
so that higher numbers mean higher priority, but the virtual network
number is ignored by Ruby except that messages on network 2 can only go
to other message buffers on network 2 (i.e., messages can’t jump from
one network to another).</p>

<p>Similarly, there is two different ways this cache can receive messages,
either as a forwarded request from the directory (e.g., another cache
requests a writable block and we have a readable copy) or as a response
to a request this controller made. The response is higher priority than
the forwarded requests.</p>

<p>Finally, there is a special message buffer, the <code class="highlighter-rouge">mandatoryQueue</code>. This
message buffer is used by the <code class="highlighter-rouge">Sequencer</code> to convert gem5 packets into
Ruby requests. Unlike the other message buffers, <code class="highlighter-rouge">mandatoryQueue</code> does
not connect to the Ruby network. Note: the name of this message buffer
is hard-coded and must be exactly “mandatoryQueue”.</p>

<p>As previously mentioned, this parameter block is converted into the
SimObject description file. Any parameters you put in this block will be
SimObject parameters that are accessible from the Python configuration
files. If you look at the generated file L1Cache_Controller.py, it will
look very familiar. Note: This is a generated file and you should never
modify generated files directly!</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">m5.params</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">m5.SimObject</span> <span class="kn">import</span> <span class="n">SimObject</span>
<span class="kn">from</span> <span class="nn">Controller</span> <span class="kn">import</span> <span class="n">RubyController</span>

<span class="k">class</span> <span class="nc">L1Cache_Controller</span><span class="p">(</span><span class="n">RubyController</span><span class="p">):</span>
    <span class="nb">type</span> <span class="o">=</span> <span class="s">'L1Cache_Controller'</span>
    <span class="n">cxx_header</span> <span class="o">=</span> <span class="s">'mem/protocol/L1Cache_Controller.hh'</span>
    <span class="n">sequencer</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">RubySequencer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">cacheMemory</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">RubyCache</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">send_evictions</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">Bool</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">requestToDir</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MessageBuffer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">responseToDirOrSibling</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MessageBuffer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">forwardFromDir</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MessageBuffer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">responseFromDirOrSibling</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MessageBuffer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
    <span class="n">mandatoryQueue</span> <span class="o">=</span> <span class="n">Param</span><span class="o">.</span><span class="n">MessageBuffer</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="state-declarations">State declarations</h2>

<p>The next part of the state machine is the state declaration. Here, we
are going to declare all of the stable and transient states for the
state machine. We will follow the naming convention in Sorin et al. For
instance, the transient state “IM_AD” corresponds to moving from
Invalid to Modified waiting on acks and data. These states come directly
from the left column of Table 8.3 in Sorin et al.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">state_declaration</span><span class="p">(</span><span class="n">State</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Cache states"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">I</span><span class="p">,</span>      <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Invalid</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Not present/Invalid"</span><span class="p">;</span>

    <span class="c1">// States moving out of I</span>
    <span class="n">IS_D</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Invalid</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Invalid, moving to S, waiting for data"</span><span class="p">;</span>
    <span class="n">IM_AD</span><span class="p">,</span>  <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Invalid</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Invalid, moving to M, waiting for acks and data"</span><span class="p">;</span>
    <span class="n">IM_A</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Busy</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Invalid, moving to M, waiting for acks"</span><span class="p">;</span>

    <span class="n">S</span><span class="p">,</span>      <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Read_Only</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Shared. Read-only, other caches may have the block"</span><span class="p">;</span>

    <span class="c1">// States moving out of S</span>
    <span class="n">SM_AD</span><span class="p">,</span>  <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Read_Only</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Shared, moving to M, waiting for acks and 'data'"</span><span class="p">;</span>
    <span class="n">SM_A</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Read_Only</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Shared, moving to M, waiting for acks"</span><span class="p">;</span>

    <span class="n">M</span><span class="p">,</span>      <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Read_Write</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Modified. Read &amp; write permissions. Owner of block"</span><span class="p">;</span>

    <span class="c1">// States moving to Invalid</span>
    <span class="n">MI_A</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Busy</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Was modified, moving to I, waiting for put ack"</span><span class="p">;</span>
    <span class="n">SI_A</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Busy</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Was shared, moving to I, waiting for put ack"</span><span class="p">;</span>
    <span class="n">II_A</span><span class="p">,</span>   <span class="n">AccessPermission</span><span class="o">:</span><span class="n">Invalid</span><span class="p">,</span>
                <span class="n">desc</span><span class="o">=</span><span class="s">"Sent valid data before receiving put ack. "</span><span class="n">Waiting</span> <span class="k">for</span> <span class="n">put</span> <span class="n">ack</span><span class="p">.</span><span class="s">";</span><span class="err">
</span><span class="s">}</span><span class="err">
</span></code></pre></div></div>

<p>Each state has an associated access permission: “Invalid”, “NotPresent”,
“Busy”, “Read_Only”, or “Read_Write”. The access permission is used
for <em>functional</em> accesses to the cache. Functional accesses are
debug-like accesses when the simulator wants to read or update the data
immediately. One example of this is reading in files in SE mode which
are directly loaded into memory.</p>

<p>For functional accesses all caches are checked to see if they have a
corresponding block with matching address. For functional reads, <em>all</em>
of the blocks with a matching address that have read-only or read-write
permission are accessed (they should all have the same data). For
functional writes, all blocks are updated with new data if they have
busy, read-only, or read-write permission.</p>

<h2 id="event-declarations">Event declarations</h2>

<p>Next, we need to declare all of the events that are triggered by
incoming messages for this cache controller. These events come directly
from the first row in Table 8.3 in Sorin et al.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">enumeration</span><span class="p">(</span><span class="n">Event</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Cache events"</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// From the processor/sequencer/mandatory queue</span>
    <span class="n">Load</span><span class="p">,</span>           <span class="n">desc</span><span class="o">=</span><span class="s">"Load from processor"</span><span class="p">;</span>
    <span class="n">Store</span><span class="p">,</span>          <span class="n">desc</span><span class="o">=</span><span class="s">"Store from processor"</span><span class="p">;</span>

    <span class="c1">// Internal event (only triggered from processor requests)</span>
    <span class="n">Replacement</span><span class="p">,</span>    <span class="n">desc</span><span class="o">=</span><span class="s">"Triggered when block is chosen as victim"</span><span class="p">;</span>

    <span class="c1">// Forwarded request from other cache via dir on the forward network</span>
    <span class="n">FwdGetS</span><span class="p">,</span>        <span class="n">desc</span><span class="o">=</span><span class="s">"Directory sent us a request to satisfy GetS. We must have the block in M to respond to this."</span><span class="p">;</span>
    <span class="n">FwdGetM</span><span class="p">,</span>        <span class="n">desc</span><span class="o">=</span><span class="s">"Directory sent us a request to satisfy GetM. We must have the block in M to respond to this."</span><span class="p">;</span>
    <span class="n">Inv</span><span class="p">,</span>            <span class="n">desc</span><span class="o">=</span><span class="s">"Invalidate from the directory."</span><span class="p">;</span>
    <span class="n">PutAck</span><span class="p">,</span>         <span class="n">desc</span><span class="o">=</span><span class="s">"Response from directory after we issue a put. This must be on the fwd network to avoid deadlock."</span><span class="p">;</span>

    <span class="c1">// Responses from directory</span>
    <span class="n">DataDirNoAcks</span><span class="p">,</span>  <span class="n">desc</span><span class="o">=</span><span class="s">"Data from directory (acks = 0)"</span><span class="p">;</span>
    <span class="n">DataDirAcks</span><span class="p">,</span>    <span class="n">desc</span><span class="o">=</span><span class="s">"Data from directory (acks &gt; 0)"</span><span class="p">;</span>

    <span class="c1">// Responses from other caches</span>
    <span class="n">DataOwner</span><span class="p">,</span>      <span class="n">desc</span><span class="o">=</span><span class="s">"Data from owner"</span><span class="p">;</span>
    <span class="n">InvAck</span><span class="p">,</span>         <span class="n">desc</span><span class="o">=</span><span class="s">"Invalidation ack from other cache after Inv"</span><span class="p">;</span>

    <span class="c1">// Special event to simplify implementation</span>
    <span class="n">LastInvAck</span><span class="p">,</span>     <span class="n">desc</span><span class="o">=</span><span class="s">"Triggered after the last ack is received"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="user-defined-structures">User-defined structures</h2>

<p>Next, we need to define some structures that we will use in other places
in this controller. The first one we will define is <code class="highlighter-rouge">Entry</code>. This is the
structure that is stored in the <code class="highlighter-rouge">CacheMemory</code>. It only needs to contain
data and a state, but it may contain any other data you want. Note: The
state that this structure is storing is the <code class="highlighter-rouge">State</code> type that was
defined above, not a hardcoded state type.</p>

<p>You can find the abstract version of this class (<code class="highlighter-rouge">AbstractCacheEntry</code>)
in <code class="highlighter-rouge">src/mem/ruby/slicc_interface/AbstractCacheEntry.hh</code>. If you want to
use any of the member functions of <code class="highlighter-rouge">AbstractCacheEntry</code>, you need to
declare them here (this isn’t used in this protocol).</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">structure</span><span class="p">(</span><span class="n">Entry</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Cache entry"</span><span class="p">,</span> <span class="n">interface</span><span class="o">=</span><span class="s">"AbstractCacheEntry"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">State</span> <span class="n">CacheState</span><span class="p">,</span>        <span class="n">desc</span><span class="o">=</span><span class="s">"cache state"</span><span class="p">;</span>
    <span class="n">DataBlock</span> <span class="n">DataBlk</span><span class="p">,</span>       <span class="n">desc</span><span class="o">=</span><span class="s">"Data in the block"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Another structure we will need is a TBE. TBE is the “transaction buffer
entry”. This stores information needed during transient states. This is
<em>like</em> an MSHR. It functions as an MSHR in this protocol, but the entry
is also allocated for other uses. In this protocol, it will store the
state (usually needed), data (also usually needed), and the number of
acks that this block is currently waiting for. The <code class="highlighter-rouge">AcksOutstanding</code> is
used for the transitions where other controllers send acks instead of
the data.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">structure</span><span class="p">(</span><span class="n">TBE</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Entry for transient requests"</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">State</span> <span class="n">TBEState</span><span class="p">,</span>         <span class="n">desc</span><span class="o">=</span><span class="s">"State of block"</span><span class="p">;</span>
    <span class="n">DataBlock</span> <span class="n">DataBlk</span><span class="p">,</span>      <span class="n">desc</span><span class="o">=</span><span class="s">"Data for the block. Needed for MI_A"</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">AcksOutstanding</span><span class="p">,</span> <span class="k">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">desc</span><span class="o">=</span><span class="s">"Number of acks left to receive."</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Next, we need a place to store all of the TBEs. This is an externally
defined class; it is defined in C++ outside of SLICC. Therefore, we need
to declare that we are going to use it, and also declare any of the
functions that we will call on it. You can find the code for the
<code class="highlighter-rouge">TBETable</code> in src/mem/ruby/structures/TBETable.hh. It is templatized on
the TBE structure defined above, which gets a little confusing, as we
will see.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">structure</span><span class="p">(</span><span class="n">TBETable</span><span class="p">,</span> <span class="n">external</span><span class="o">=</span><span class="s">"yes"</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">TBE</span> <span class="n">lookup</span><span class="p">(</span><span class="n">Addr</span><span class="p">);</span>
  <span class="kt">void</span> <span class="n">allocate</span><span class="p">(</span><span class="n">Addr</span><span class="p">);</span>
  <span class="kt">void</span> <span class="n">deallocate</span><span class="p">(</span><span class="n">Addr</span><span class="p">);</span>
  <span class="kt">bool</span> <span class="n">isPresent</span><span class="p">(</span><span class="n">Addr</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="highlighter-rouge">external="yes"</code> tells SLICC to not look for the definition of this
structure. This is similar to declaring a variable <code class="highlighter-rouge">extern</code> in C/C++.</p>

<h2 id="other-declarations-and-definitions-required">Other declarations and definitions required</h2>

<p>Finally, we are going to go through some boilerplate of declaring
variables, declaring functions in <code class="highlighter-rouge">AbstractController</code> that we will use
in this controller, and defining abstract functions in
<code class="highlighter-rouge">AbstractController</code>.</p>

<p>First, we need to have a variable that stores a TBE table. We have to do
this in SLICC because it is not until this time that we know the true
type of the TBE table since the TBE type was defined above. This is some
particularly tricky (or nasty) code to get SLICC to generate the right
C++ code. The difficulty is that we want templatize <code class="highlighter-rouge">TBETable</code> based on
the <code class="highlighter-rouge">TBE</code> type above. The key is that SLICC mangles the names of all
types declared in the machine with the machine’s name. For instance,
<code class="highlighter-rouge">TBE</code> is actually L1Cache_TBE in C++.</p>

<p>We also want to pass a parameter to the constructor of the <code class="highlighter-rouge">TBETable</code>.
This is a parameter that is actually part of the <code class="highlighter-rouge">AbstractController</code>,
thus we need to use the C++ name for the variable since it doesn’t have
a SLICC name.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">TBETable</span> <span class="n">TBEs</span><span class="p">,</span> <span class="k">template</span><span class="o">=</span><span class="s">"&lt;L1Cache_TBE&gt;"</span><span class="p">,</span> <span class="n">constructor</span><span class="o">=</span><span class="s">"m_number_of_TBEs"</span><span class="p">;</span>
</code></pre></div></div>

<p>If you can understand the above code, then you are an official SLICC
ninja!</p>

<p>Next, any functions that are part of AbstractController need to be
declared, if we are going to use them in the rest of the file. In this
case, we are only going to use <code class="highlighter-rouge">clockEdge()</code>:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Tick</span> <span class="nf">clockEdge</span><span class="p">();</span>
</code></pre></div></div>

<p>There are a few other functions we’re going to use in actions. These
functions are used in actions to set and unset implicit variables
available in action code-blocks. Action code blocks will be explained in
detail in the action section &lt;MSI-actions-section&gt;. These may be
needed when a transition has many actions.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">set_cache_entry</span><span class="p">(</span><span class="n">AbstractCacheEntry</span> <span class="n">a</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">unset_cache_entry</span><span class="p">();</span>
<span class="kt">void</span> <span class="nf">set_tbe</span><span class="p">(</span><span class="n">TBE</span> <span class="n">b</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">unset_tbe</span><span class="p">();</span>
</code></pre></div></div>

<p>Another useful function is <code class="highlighter-rouge">mapAddressToMachine</code>. This allows us to
change the address mappings for banked directories or caches at runtime
so we don’t have to hardcode them in the SLICC file.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">MachineID</span> <span class="nf">mapAddressToMachine</span><span class="p">(</span><span class="n">Addr</span> <span class="n">addr</span><span class="p">,</span> <span class="n">MachineType</span> <span class="n">mtype</span><span class="p">);</span>
</code></pre></div></div>

<p>Finally, you can also add any functions you may want to use in the file
and implement them here. For instance, it is convenient to access cache
blocks by address with a single function. Again, in this function there
is some SLICC trickery. We need to access “by pointer” since the cache
block is something that we need to be mutable later (“by reference”
would have been a better name). The cast is also necessary since we
defined a specific <code class="highlighter-rouge">Entry</code> type in the file, but the <code class="highlighter-rouge">CacheMemory</code> holds
the abstract type.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Convenience function to look up the cache entry.</span>
<span class="c1">// Needs a pointer so it will be a reference and can be updated in actions</span>
<span class="n">Entry</span> <span class="nf">getCacheEntry</span><span class="p">(</span><span class="n">Addr</span> <span class="n">address</span><span class="p">),</span> <span class="n">return_by_pointer</span><span class="o">=</span><span class="s">"yes"</span> <span class="p">{</span>
    <span class="k">return</span> <span class="k">static_cast</span><span class="p">(</span><span class="n">Entry</span><span class="p">,</span> <span class="s">"pointer"</span><span class="p">,</span> <span class="n">cacheMemory</span><span class="p">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">address</span><span class="p">));</span>
<span class="err">}</span>
</code></pre></div></div>

<p>The next set of boilerplate code rarely changes between different
protocols. There’s a set of functions that are pure-virtual in
<code class="highlighter-rouge">AbstractController</code> that we must implement.</p>

<dl>
  <dt><code class="highlighter-rouge">getState</code></dt>
  <dd>Given a TBE, cache entry, and address return the state of the block.
This is called on the block to decide which transition to execute
when an event is triggered. Usually, you return the state in the TBE
or cache entry, whichever is valid.</dd>
  <dt><code class="highlighter-rouge">setState</code></dt>
  <dd>Given a TBE, cache entry, and address make sure the state is set
correctly on the block. This is called at the end of the transition
to set the final state on the block.</dd>
  <dt><code class="highlighter-rouge">getAccessPermission</code></dt>
  <dd>Get the access permission of a block. This is used during functional
access to decide whether or not to functionally access the block. It
is similar to <code class="highlighter-rouge">getState</code>, get the information from the TBE if valid,
cache entry, if valid, or the block is not present.</dd>
  <dt><code class="highlighter-rouge">setAccessPermission</code></dt>
  <dd>Like <code class="highlighter-rouge">getAccessPermission</code>, but sets the permission.</dd>
  <dt><code class="highlighter-rouge">functionalRead</code></dt>
  <dd>Functionally read the data. It is possible the TBE has more
up-to-date information, so check that first. Note: testAndRead/Write
defined in src/mem/ruby/slicc_interface/Util.hh</dd>
  <dt><code class="highlighter-rouge">functionalWrite</code></dt>
  <dd>Functionally write the data. Similarly, you may need to update the
data in both the TBE and the cache entry.</dd>
</dl>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">State</span> <span class="nf">getState</span><span class="p">(</span><span class="n">TBE</span> <span class="n">tbe</span><span class="p">,</span> <span class="n">Entry</span> <span class="n">cache_entry</span><span class="p">,</span> <span class="n">Addr</span> <span class="n">addr</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// The TBE state will override the state in cache memory, if valid</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span> <span class="n">tbe</span><span class="p">.</span><span class="n">TBEState</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">// Next, if the cache entry is valid, it holds the state</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">CacheState</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">// If the block isn't present, then it's state must be I.</span>
    <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="n">State</span><span class="o">:</span><span class="n">I</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">setState</span><span class="p">(</span><span class="n">TBE</span> <span class="n">tbe</span><span class="p">,</span> <span class="n">Entry</span> <span class="n">cache_entry</span><span class="p">,</span> <span class="n">Addr</span> <span class="n">addr</span><span class="p">,</span> <span class="n">State</span> <span class="n">state</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">))</span> <span class="p">{</span> <span class="n">tbe</span><span class="p">.</span><span class="n">TBEState</span> <span class="o">:=</span> <span class="n">state</span><span class="p">;</span> <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">))</span> <span class="p">{</span> <span class="n">cache_entry</span><span class="p">.</span><span class="n">CacheState</span> <span class="o">:=</span> <span class="n">state</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="n">AccessPermission</span> <span class="nf">getAccessPermission</span><span class="p">(</span><span class="n">Addr</span> <span class="n">addr</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">TBE</span> <span class="n">tbe</span> <span class="o">:=</span> <span class="n">TBEs</span><span class="p">[</span><span class="n">addr</span><span class="p">];</span>
    <span class="k">if</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">L1Cache_State_to_permission</span><span class="p">(</span><span class="n">tbe</span><span class="p">.</span><span class="n">TBEState</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">Entry</span> <span class="n">cache_entry</span> <span class="o">:=</span> <span class="n">getCacheEntry</span><span class="p">(</span><span class="n">addr</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">))</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">L1Cache_State_to_permission</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">.</span><span class="n">CacheState</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">AccessPermission</span><span class="o">:</span><span class="n">NotPresent</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">setAccessPermission</span><span class="p">(</span><span class="n">Entry</span> <span class="n">cache_entry</span><span class="p">,</span> <span class="n">Addr</span> <span class="n">addr</span><span class="p">,</span> <span class="n">State</span> <span class="n">state</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">cache_entry</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">cache_entry</span><span class="p">.</span><span class="n">changePermission</span><span class="p">(</span><span class="n">L1Cache_State_to_permission</span><span class="p">(</span><span class="n">state</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">functionalRead</span><span class="p">(</span><span class="n">Addr</span> <span class="n">addr</span><span class="p">,</span> <span class="n">Packet</span> <span class="o">*</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">TBE</span> <span class="n">tbe</span> <span class="o">:=</span> <span class="n">TBEs</span><span class="p">[</span><span class="n">addr</span><span class="p">];</span>
    <span class="k">if</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">testAndRead</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">tbe</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="n">testAndRead</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">getCacheEntry</span><span class="p">(</span><span class="n">addr</span><span class="p">).</span><span class="n">DataBlk</span><span class="p">,</span> <span class="n">pkt</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">functionalWrite</span><span class="p">(</span><span class="n">Addr</span> <span class="n">addr</span><span class="p">,</span> <span class="n">Packet</span> <span class="o">*</span><span class="n">pkt</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">num_functional_writes</span> <span class="o">:=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="n">TBE</span> <span class="n">tbe</span> <span class="o">:=</span> <span class="n">TBEs</span><span class="p">[</span><span class="n">addr</span><span class="p">];</span>
    <span class="k">if</span><span class="p">(</span><span class="n">is_valid</span><span class="p">(</span><span class="n">tbe</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">num_functional_writes</span> <span class="o">:=</span> <span class="n">num_functional_writes</span> <span class="o">+</span>
            <span class="n">testAndWrite</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">tbe</span><span class="p">.</span><span class="n">DataBlk</span><span class="p">,</span> <span class="n">pkt</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">num_functional_writes</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">num_functional_writes</span> <span class="o">:=</span> <span class="n">num_functional_writes</span> <span class="o">+</span>
            <span class="n">testAndWrite</span><span class="p">(</span><span class="n">addr</span><span class="p">,</span> <span class="n">getCacheEntry</span><span class="p">(</span><span class="n">addr</span><span class="p">).</span><span class="n">DataBlk</span><span class="p">,</span> <span class="n">pkt</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">num_functional_writes</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

  <br>

  <!-- RETRIVE PREVIOUS PAGE LINK -->
  
    
  
    
  
    
  
    
  

  <!-- RETRIEVE NEXT PAGE LINK -->
  
    
  
    
  
    
  
    
  


  <div class="navbuttons">
    
      <a href=""><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a>
    

    
      <a href=""><button type="button" class="btn btn-outline-primary">NEXT</button></a>
    
  </div>
</div>

	</main>
	<footer class="page-footer">
	<div class="container">
		<div class="row">

			<div class="col-12 col-sm-4">
				<p>gem5</p>
				<p><a href="/about">About</a></p>
				<p><a href="/publications">Publications</a></p>
				<p><a href="/contributing">Contributing</a></p>
				<p><a href="/governance">Governance</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Docs</p>
				<p><a href="/documentation">Documentation</a></p>
				<p><a href="http://gem5.org/Documentation">Old Documentation</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5">Source</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Help</p>
				<p><a href="/search">Search</a></p>
				<p><a href="/mailing_lists">Mailing Lists</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Website Source</a></p>
			<br></div>

		</div>
	</div>
</footer>


	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
	<script src="https://unpkg.com/commentbox.io/dist/commentBox.min.js"></script>

	<script>
	  // When the user scrolls down 20px from the top of the document, show the button
	  window.onscroll = function() {scrollFunction()};

	  function scrollFunction() {
	      if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
	          document.getElementById("myBtn").style.display = "block";
	      } else {
	          document.getElementById("myBtn").style.display = "none";
	      }
	  }

	  // When the user clicks on the button, scroll to the top of the document
	  function topFunction() {
	      document.body.scrollTop = 0;
	      document.documentElement.scrollTop = 0;
	  }

		import commentBox from 'commentbox.io';
		// or
		const commentBox = require('commentbox.io');
		// or if using the CDN, it will be available as a global "commentBox" variable.

		commentBox('my-project-id');

	</script>

</body>


</html>
